import json
import time
from decimal import Decimal

from django import http
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import transaction
from django.shortcuts import render, redirect, reverse

# Create your views here.
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection

from apps.goods.models import SKU
from apps.orders.models import OrderGoods, OrderInfo
from apps.users.models import Address
from utils.response_code import RETCODE
from utils.views import LoginRequiredJSONMixin


class OrdersView(LoginRequiredMixin, View):
    """订单页面"""

    def get(self, request):
        """提供订单结算页面"""
        # 获取登录用户
        user = request.user
        # 查询地址信息
        try:
            addresses = Address.objects.filter(user=request.user, is_deleted=False)
        except Address.DoesNotExist:
            # 如果地址为空，渲染模板时会判断，并跳转到地址编辑页面
            addresses = None
            # 获取登录用户

        # 从Redis购物车中查询出被勾选的商品信息
        redis_conn = get_redis_connection('carts')
        redis_cart = redis_conn.hgetall('carts_%s' % user.id)

        if not redis_conn:
            messages.success(request, "缺少商品")
            return redirect(reverse('shoppingcart:carts'))

        cart = {}
        for sku_id in redis_cart:
            cart[int(sku_id)] = int(redis_cart[sku_id])
        # 准备初始值
        total_count = 0
        total_amount = Decimal(0.00)
        # 查询商品信息
        skus = SKU.objects.filter(id__in=cart.keys())
        for sku in skus:
            sku.count = cart[sku.id]
            sku.amount = sku.count * sku.price
            # 计算总数量和总金额
            total_count += sku.count
            total_amount += sku.count * sku.price
            print(total_count, '=================')
        # 补充运费
        freight = Decimal('10.00')

        # 渲染界面
        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_amount+freight
        }
        return render(request, 'order.html', context)


# class OrderCommitView(LoginRequiredJSONMixin, View):
#     """订单提交"""
#
#     def post(self, request):
#         """保存订单信息和订单商品信息"""
#         # 获取当前要保存的订单数据
#         json_dict = json.loads(request.body.decode())
#         address_id = json_dict.get('address_id')
#         pay_method = json_dict.get('pay_method')
#
#         # 校验参数
#         if not all([address_id, pay_method]):
#             return http.HttpResponseBadRequest('缺少必传参数')
#         # 判断address_id是否合法
#         try:
#             address = Address.objects.get(id=address_id)
#             # 判断这个收货地址是否属于当前登录用户
#             if address.user != request.user:
#                 # 如果不属于当前用户，那么返回错误信息信息
#                 return http.HttpResponseBadRequest('参数address_id错误')
#         except Exception:
#             return http.HttpResponseBadRequest('参数address_id错误')
#         # 判断pay_method是否合法
#         if int(pay_method) not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
#             return http.HttpResponseBadRequest('参数pay_method错误')
#
#         # 获取登录用户
#         user = request.user
#         # 生成订单编号：年月日时分秒+用户编号
#         order_id = timezone.now().strftime('%Y%m%d%H%M%S') + '%09d' % user.id
#
#         # 显式的开启一个事务
#         with transaction.atomic():
#             # 创建事务保存点
#             save_id = transaction.savepoint()
#             try:
#
#                 # 保存订单基本信息 OrderInfo（一）
#                 order = OrderInfo.objects.create(
#                     order_id=order_id,
#                     user=user,
#                     address=address,
#                     total_count=0,
#                     total_amount=Decimal('0'),
#                     freight=Decimal('00.00'),
#                     pay_method=pay_method,
#                     status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM[
#                         'ALIPAY'] else
#                     OrderInfo.ORDER_STATUS_ENUM['UNSEND']
#                 )
#
#                 # 从redis读取购物车中被勾选的商品信息
#                 redis_conn = get_redis_connection('carts')
#                 redis_cart = redis_conn.hgetall('carts_%s' % user.id)
#
#                 carts = {}
#                 for sku_id in redis_cart:
#                     carts[int(sku_id)] = int(redis_cart[sku_id])
#                 sku_ids = carts.keys()
#
#                 # 遍历购物车中被勾选的商品信息
#                 for sku_id in sku_ids:
#                     # ------- 修改了代码-------
#                     for sql_loop in range(3):
#                         # 查询SKU信息
#                         sku = SKU.objects.get(id=sku_id)
#
#                         print("{}--正在下单id={}".format(request.user.username, sku_id))
#
#                         # ------- 修改了代码-------
#                         # 读取原始库存
#                         origin_stock = sku.stock
#                         origin_sales = sku.sales
#
#                         # 判断SKU库存
#                         sku_count = carts[sku.id]
#                         if sku_count > origin_stock:
#                             # 事务回滚
#                             transaction.savepoint_rollback(save_id)
#                             return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})
#
#                         # 乐观锁更新库存和销量
#                         new_stock = origin_stock - sku_count
#                         new_sales = origin_sales + sku_count
#                         result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock,
#                                                                                           sales=new_sales)
#                         # 如果下单失败，但是库存足够时，继续下单，直到下单成功或者库存不足为止
#                         if result == 0:
#                             if sql_loop == 2:
#                                 # 事务回滚
#                                 transaction.savepoint_rollback(save_id)
#                                 return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '下单失败2'})
#                             else:
#                                 continue
#                         else:
#                             break
#
#                     # 保存订单商品信息 OrderGoods（多）
#                     OrderGoods.objects.create(
#                         order=order,
#                         sku=sku,
#                         count=sku_count,
#                         price=sku.price,
#                     )
#
#                     # 保存商品订单中总价和总数量
#                     order.total_count += sku_count
#                     order.total_amount += sku_count * sku.price
#
#                     # 测试用的，可以删除（注意下方的7是当前我在测试时一个用户的id小于7而另外一个是7，所以才写的7，根据实际编写即可）
#                     # if request.user.id < 7:
#                     #     for i in range(10):
#                     #         print("用户{}正在延时{}提交中...".format(request.user.username, i + 1))
#                     #         time.sleep(1)
#
#                 # 添加邮费和保存订单信息
#                 order.total_amount += order.freight
#                 order.save()
#             except Exception as e:
#                 transaction.savepoint_rollback(save_id)
#                 return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})
#
#             # 提交订单成功，显式的提交一次事务
#             transaction.savepoint_commit(save_id)
#
#         # 清除购物车中已结算的商品
#         print(type(user.id))
#         pl = redis_conn.pipeline()
#         pl.hdel('carts_%s' % user.id)
#         pl.execute()
#
#         # 响应提交订单结果
#         return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order.order_id})

class OrderCommitView(LoginRequiredJSONMixin, View):
    """订单提交"""

    def post(self, request):
        """保存订单信息和订单商品信息"""
        # 获取当前要保存的订单数据
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')

        # 校验参数
        if not all([address_id, pay_method]):
            return http.HttpResponseBadRequest('缺少必传参数')
        # 判断address_id是否合法
        try:
            address = Address.objects.get(id=address_id)
            # 判断这个收货地址是否属于当前登录用户
            if address.user != request.user:
                # 如果不属于当前用户，那么返回错误信息信息
                return http.HttpResponseBadRequest('参数address_id错误')
        except Exception:
            return http.HttpResponseBadRequest('参数address_id错误')
        # 判断pay_method是否合法
        if int(pay_method) not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.HttpResponseBadRequest('参数pay_method错误')

        # 获取登录用户
        user = request.user
        # 生成订单编号：年月日时分秒+用户编号
        order_id = timezone.now().strftime('%Y%m%d%H%M%S') + '%09d' % user.id

        # 显式的开启一个事务
        with transaction.atomic():
            # 创建事务保存点
            save_id = transaction.savepoint()
            try:

                # 保存订单基本信息 OrderInfo（一）
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('0'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM[
                        'ALIPAY'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNSEND']
                )

                # 从redis读取购物车中被勾选的商品信息
                redis_conn = get_redis_connection('carts')
                redis_cart = redis_conn.hgetall('carts_%s' % user.id)
                selected = redis_conn.smembers('selected_%s' % user.id)
                carts = {}
                for sku_id in redis_cart:
                    carts[int(sku_id)] = int(redis_cart[sku_id])
                sku_ids = carts.keys()

                # 遍历购物车中被勾选的商品信息
                for sku_id in sku_ids:
                    # ------- 修改了代码-------
                    for sql_loop in range(3):
                        # 查询SKU信息
                        sku = SKU.objects.get(id=sku_id)

                        print("{}--正在下单id={}".format(request.user.username, sku_id))

                        # ------- 修改了代码-------
                        # 读取原始库存
                        origin_stock = sku.stock
                        origin_sales = sku.sales

                        # 判断SKU库存
                        sku_count = carts[sku.id]
                        if sku_count > origin_stock:
                            # 事务回滚
                            transaction.savepoint_rollback(save_id)
                            return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})

                        # 乐观锁更新库存和销量
                        new_stock = origin_stock - sku_count
                        new_sales = origin_sales + sku_count
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock,
                                                                                          sales=new_sales)
                        # 如果下单失败，但是库存足够时，继续下单，直到下单成功或者库存不足为止
                        if result == 0:
                            if sql_loop == 2:
                                # 事务回滚
                                transaction.savepoint_rollback(save_id)
                                return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '下单失败2'})
                            else:
                                continue
                        else:
                            break

                    # 保存订单商品信息 OrderGoods（多）
                    OrderGoods.objects.create(
                        order=order,
                        sku=sku,
                        count=sku_count,
                        price=sku.price,
                    )

                    # 保存商品订单中总价和总数量
                    order.total_count += sku_count
                    order.total_amount += sku_count * sku.price

                    # 测试用的，可以删除（注意下方的7是当前我在测试时一个用户的id小于7而另外一个是7，所以才写的7，根据实际编写即可）
                    # if request.user.id < 7:
                    #     for i in range(10):
                    #         print("用户{}正在延时{}提交中...".format(request.user.username, i + 1))
                    #         time.sleep(1)

                # 添加邮费和保存订单信息
                order.total_amount += order.freight
                order.save()
            except Exception as e:
                transaction.savepoint_rollback(save_id)
                return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})

            # 提交订单成功，显式的提交一次事务
            transaction.savepoint_commit(save_id)

        # 清除购物车中已结算的商品
        pl = redis_conn.pipeline()

        pl.hdel('carts_%s' % user.id, sku_id)
        # pl.srem('selected_%s' % user.id, *selected)

        pl.execute()

        # 响应提交订单结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order.order_id})


class OrderSuccessView(LoginRequiredMixin, View):
    """提交订单成功"""

    def get(self, request):
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')

        context = {
            'order_id':order_id,
            'payment_amount':payment_amount,
            'pay_method':pay_method
        }
        return render(request, 'ok.html', context)
